#include "message_handle.h"
#include "cJSON.h"

#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

/* ---------- 内部工具 ---------- */
static char *make_core(enum CM_TYPE type, const char *uuid, const char *payload_json)
{
    cJSON *root = cJSON_CreateObject();
    cJSON_AddNumberToObject(root, "t", (double)type);
    cJSON_AddStringToObject(root, "i", uuid);
    cJSON_AddRawToObject(root, "p", payload_json); /* 直接塞 JSON 字符串 */
    char *json = cJSON_PrintUnformatted(root);
    cJSON_Delete(root);
    size_t len = strlen(json);
    char *line = (char *)malloc(len + 2);
    memcpy(line, json, len);
    line[len] = '\n';
    line[len + 1] = '\0';
    free(json);
    return line;
}

/* ---------- 工厂 ---------- */
char *cm_make_connect(const char *nick)
{
    char payload[64];
    snprintf(payload, sizeof(payload), "{\"nick\":\"%s\"}", nick);
    char uuid[37];
    cm_new_uuid(uuid);
    return make_core(CM_CONNECT, uuid, payload);
}

char *cm_make_normal(const char *text)
{
    char payload[256];
    snprintf(payload, sizeof(payload), "{\"text\":\"%s\"}", text);
    char uuid[37];
    cm_new_uuid(uuid);
    return make_core(CM_NORMAL, uuid, payload);
}

char *cm_make_p2p(const char *text, const char *to_uuid)
{
    char payload[256];
    snprintf(payload, sizeof(payload), "{\"text\":\"%s\",\"to\":\"%s\"}", text, to_uuid);
    char uuid[37];
    cm_new_uuid(uuid);
    return make_core(CM_P2P, uuid, payload);
}

char *cm_make_ack(const char *uuid)
{
    return make_core(CM_ACK, uuid, "{}");
}

char *cm_make(enum CM_TYPE type, const char *uuid, const char *payload_json)
{
    return make_core(type, uuid[0] ? uuid : (cm_new_uuid((char[37]){ 0 }), (char[37]){ 0 }), payload_json);
}

/* ---------- 解析 ---------- */
cJSON *cm_parse(const char *line)
{
    cJSON *root = cJSON_Parse(line);
    if (!root)
        return NULL;
    if (!cJSON_HasObjectItem(root, "t") ||
        !cJSON_HasObjectItem(root, "i") ||
        !cJSON_HasObjectItem(root, "p")) {
        cJSON_Delete(root);
        return NULL;
    }
    return root;
}

enum CM_TYPE cm_type(const cJSON *msg)
{
    return (enum CM_TYPE)cJSON_GetObjectItem(msg, "t")->valueint;
}
const char *cm_uuid(const cJSON *msg)
{
    return cJSON_GetObjectItem(msg, "i")->valuestring;
}
const cJSON *cm_payload(const cJSON *msg)
{
    return cJSON_GetObjectItem(msg, "p");
}

/* ---------- UUID 生成 ---------- */
void cm_new_uuid(char out[42])
{
    static uint64_t counter = 0;
    uint64_t t = (uint64_t)time(NULL) << 32;
    t |= (__sync_fetch_and_add(&counter, 1) & 0xFFFFFFFF);
    snprintf(out, 42, "%016" PRIX64 "-%04X-%04X-%04X-%04X%04X",
             t, rand() & 0xFFFF, rand() & 0xFFFF,
             rand() & 0xFFFF, rand() & 0xFFFF, rand() & 0xFFFF);
}